Node.js TCP Server
TCP Server 通过 Node 中的 net 模块来实现 TCP 四层模型(应用层、传输层、网络层、链路层)
| Id | Name | Info | Protocol |
|---|---|---|---|
| 1 | 链路层(Link layer) | 负责在以太网、Wifi 底层网络发送数据包,并通过网卡、使用 MAC 地址来标记网络上的设备 | GPRS、IEEE、IPoe、Localhost、TRILL、IPoAC、FDDI、NAK\NACK、SEND、frame\frame relay、ATM、Data Link Layer、PPP、STP、L2TP、ARQ、CDPD、LLDP、LCP、Link Aggregation、HDLC |
| 2 | 网络层\网络互联层(Internet layer) | 定义了 IP 地址的概念,通过 IP 地址取代 MAC 地址,并将局域网、广域网链接成一个虚拟网络,主要目的就是 将 IP 地址翻译成 MAC 地址就可查找设备 | IPsec、IPv4\IPv5\IPv6\IPv9、 IP Address、x.25、IPX、ICMP\ICMPv6、IGMP、DDP、Mobile IP、Network Layer、PPP、RSVP、Anti-replay |
| 3 | 传输层(Transport layer) | 保证数据在 IP 地址标记的两点之间进行传输 | TCP、UDP、TLS\SSL、DCCP、SCTP、RSVP |
| 4 | 应用层(Application layer) | 直接与应用程序和接口结合,并提供常见的应用服务 | DHCP、DNS、FTP、gopher、HTTP\HTTP-2、IMAP4、IRC、NNTP、XMPP、POP3、SIP、SMTP、SNMP、SSH、TELNET、RPC、RTCP、RTP、RTSP、SDP、SOAP、GTP、STUN、NTP、SSDP |
对于每个网络层次,Node 都提供了相应的模块,如 http、net、tls/crypto、dgram 等,其中 net、http、dgram 模块分别实现和提供 TCP、HTTP 的通信,其中 http 为应用层模块,而 net 为传输层模块。
1 |
|
创建一个 TCP 服务可以通过 net.createServer 方法进行创建,可通过 server.listen 来设置服务的监听端口以及,当然一旦运行服务时除发的还是 server 下的 listening 事件,因此也支持另一种写法:
net.Server()
1 | var net = require('net') |
除此之外 server 还支持另外几种 TCP 事件:
| Id | Name | Info |
|---|---|---|
| 1 | listening | 调用 server.listen(),即当开始监听时候除发 |
| 2 | connection | 当有新创建时后除发,回调的参数是 socket 连接的对象 |
| 3 | close | 当关闭时触发,回调函数没有参数 |
| 4 | error | 当 TCP 服务发生错误时触发,回调参数为 error |
1 | var net = require('net') |
server.address()
如果需要监听 IP 套接字,也就是套接字地址(socket address),可以通过 server.address() 方法来实现,他主要提供了三个服务器绑定的 address 以及 family 和 port
1 | var net = require('net') |
需要注意的是如果监听的端口号是 IPv6 地址,那么
address则返回::
server.getConnections()
.server.getConnections 方法用于异步获取服务器上的并发连接数,回调参数分为 err 和 count
1 | const net = require("net") |
之后我们分别通过 GET 请求 http://127.0.0.1:8210/ 并通过代理访问 uri 则有三个 IP 访问,因此分别依次循环输出 This is Client count: 1~3
Server at Client 之间的通信
Server
服务端主要用于接收客户端所发送的消息,因此只需要通过 data 事件来接收数据时进行输出,在收到数据之前首先通过 address() 来将转换为 JSON 格式并输出,并通过 socket.bytesWritten 来计算客户端所发送的字节数,最后通过 socket.bytesRead 方法来统计书数据的大小。
1 | const net = require('net') |
Client
在 Server 与 Client 建立链接的过程中,客户端扮演的是数据发送者的身份,而他主要的作用就是与服务端建立链接并发送数据,之后监听服务端的状态,在这期间主通过 client.connect 来链接服务,之后使用其 client.write 来写入数据并发送。
net.Socket 类
API
对于 net.Socket 相关的 API Node 提供了多种方法:
| Id | Name | Info |
|---|---|---|
| 1 | socket.address() | 返回操作系统报告并绑定 address,和套接字的 port 以及 family 等 |
| 2 | socket.bytesRead() | 接收的字节数 |
| 3 | socket.bytesWritten() | 发送的字节数 |
| 4 | socket.connect(options[,sonnectListener]) | 指定套接字链接 |
| options | ||
port 套接字应该链接到的端口(必填) |
||
host 套接字应连接到的主机(默认为 localhost) |
||
localAddress 套接字应该链接到本地地址 |
||
localPort 套接字应链接本地端口 |
||
family IP 堆栈的版本(通常是 IPv6、IPv4或0,而 0 表示 允许 IPv4/6 地址) |
||
hints 可选的 dns.lookup() 提示(主机名) |
||
lookup 自定义查找函数(默认 dns.lookup()) |
||
| 5 | socket.connect(port[,host][,connectListener]) | 指定套接字链接 |
port 客户端应该链接到的端口 |
||
host 客户端应该链接到的主机 |
||
connectListener 方法的常用参数,将被添加为 connect 事件监听 |
||
| 6 | socket.destroyed 半关闭套接字,服务端关闭时发送数据包给客户端,客户端关闭 |
|
| 7 | socket.localAddress | 远程客户端链接本地 IP 地址(以 IP 地址的字符串形式表示,如 0.0.0.0) |
| 8 | socket.localPort(socket.remotePort) | 本地端口数字表示(如 8210) |
| 9 | socket.remoteAddress | 远程 IP 地址的字符串形式输出(如 74.125.127.100 或 2001:4860:a005::68) |
| 10 | socket.remoteFamily | 远程 IP 系列的字符串形式表示(如 IPv6 或 IPv4) |
| 11 | socket.setTimeout(socket.timeout) | 用于进行设置连接(如果 timeout 为 0,则禁用空闲超时) |
| 12 | socket.setKeepAlive() | 用于设置和i长连接 |
| 13 | socket.destroy()\socket.destroyed | 当错误发生时,用于销毁 socket,以确保这个 socket 上不会有其他 IO 操作 |
事件
| Id | Name | Info |
|---|---|---|
| 1 | close | 当链接断开时触发,假设因为传输错误导致断开,则参数为 err |
| 2 | connect | 当建立成功套接字链接时触发 |
| 3 | data | 接收到数据时触发 |
| 4 | drain | 当写缓存空了时触发 |
| 5 | end | 当另一端结束时触发 |
| 6 | error | 当错误时触发 |
| 7 | lookup | 当解析完主机名后触发 |
| 8 | ready | 当套接字准备好使用时触发 |
| 9 | timeout | 提示用户 socket 超时,需要手动关闭链接 |
1 | const net = require('net') |
